package org.example.atomictest;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author zhengdp
 * @Description 原子引用类型 测试
 * @Date 2022/11/19 21:45
 * @Created by zhengdp
 */
public class AtomicReferenceTest {
    public static void main(String[] args) {
        DecimalAccount.demo(new DecimalAccountCas(new BigDecimal("10000")));
    }

    static class DecimalAccountCas implements DecimalAccount {

        private AtomicReference<BigDecimal> balance;

        public DecimalAccountCas(BigDecimal balance){
            this.balance = new AtomicReference<>(balance);
        }

        @Override
        public BigDecimal getBalance() {
            return balance.get();
        }

        @Override
        public void withDraw(BigDecimal amount) {
            while(true) {
                BigDecimal prev = balance.get();
                BigDecimal next = prev.subtract(amount);
                if(balance.compareAndSet(prev,next)) {
                    break;
                }
            }
        }
    }

    interface DecimalAccount {
        // 获取余额
        BigDecimal getBalance();

        // 取款
        void withDraw(BigDecimal amount);

        static void demo(DecimalAccount account) {
            List<Thread> ts = new ArrayList<>();
            for( int i  = 0; i < 1000 ; i ++){
                ts.add(new Thread(() -> {
                    account.withDraw(BigDecimal.TEN);
                }));
            }
            long start = System.nanoTime();
            ts.forEach(Thread::start);
            ts.forEach(t -> {
                try {
                    // 等待线程执行结束
                    t.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
            long end = System.nanoTime();
            System.out.println(account.getBalance() + " cost: " + (end-start)/1000_000 + " ms");
        }
    }

}
